class MyPromise {
  constructor(fn) {
    this.callbacks = [];
    this.state = "PENDING";
    this.value = null;

    fn(this._resolve.bind(this), this._reject.bind(this));
  }

  then(onFulilled, onRejected) {
    console.log("then---", onFulilled, onRejected);
    return new MyPromise((resolve, reject) => {
      this._handle({
        onFulilled: onFulilled || null,
        onRejected: onRejected || null,
        resolve,
        reject,
      });
    });
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }

  _handle(callback) {
    if (this.state === "PENDING") {
      this.callbacks.push(callback);

      return;
    }

    let cb =
      this.state === "FULFILLED" ? callback.onFulfilled : callback.onRejected;
    if (!cb) {
      cb = this.state === "FULFILLED" ? callback.resolve : callback.reject;
      cb(this.value);

      return;
    }

    let ret;

    try {
      ret = cb(this.value);
      cb = this.state === "FULFILLED" ? callback.resolve : callback.reject;
    } catch (error) {
      ret = error;
      cb = callback.reject;
    } finally {
      cb(ret);
    }
  }

  _resolve(value) {
    console.log("_resolve", typeof value);
    if (value && (typeof value === "object" || typeof value === "function")) {
      let then = value.then;

      if (typeof then === "function") {
        then.call(value, this._resolve.bind(this), this._reject.bind(this));

        return;
      }
    }

    this.state === "FULFILLED";
    this.value = value;
    this.callbacks.forEach((fn) => this._handle(fn));
  }

  _reject(error) {
    this.state === "REJECTED";
    this.value = error;
    this.callbacks.forEach((fn) => this._handle(fn));
  }
}

const test1 = new MyPromise(function (resolve, reject) {
  resolve(100);
});
test1.then((value) => console.log("value", value));
console.log("test1", test1);

// const p1 = new MyPromise(function (resolve, reject) {
//   setTimeout(() => reject(new Error("fail")), 3000);
// });
// console.log('p1---', p1)
// const p2 = new MyPromise(function (resolve, reject) {
//   setTimeout(() => resolve(p1), 1000);
// });

// p2.then((result) => console.log(result)).catch((error) => console.log(error));
